
#include <string.h>
#include "btstack_event.h"
#include "platform_api.h"
#include "ingsoc.h"
#include "ing_ram_code.h"
#include "User_Led_Ws2812_Drive.h"
#include "FreeRTOS.h"
#include "task.h"

volatile uint8_t Test_Dma_Send_OK = 0;
static uint8_t on_off_status = 0;
static _RAM_CODE_ void led_mode_show(uint32_t color);


#define COLOR_BLACK      (0x00000000)
#define COLOR_RED        (0x000000ff)
#define COLOR_ORANGE     (0x00003eff)
#define COLOR_YELLOW     (0x0000ffff)
#define COLOR_GREEN      (0x0000ff00)
#define COLOR_QING       (0x00ffff00)
#define COLOR_BLUE       (0x00ff0000)
#define COLOR_PURPLE     (0x00ff005f)
#define COLOR_PINK       (0x00ff00ff)
#define COLOR_WHITE      (0x00ffffff)


uint8_t Led_R_Data[RGB_LED_MAX_NUM] = {0};
uint8_t Led_G_Data[RGB_LED_MAX_NUM] = {0};
uint8_t Led_B_Data[RGB_LED_MAX_NUM] = {0};

uint32_t ledData[TRANS_DATA_NUM+1] __attribute__ ((aligned (4))) = {0};

static uint8_t LED_SpiInit(SSP_TypeDef * SPI_BASE)
{
    apSSP_sDeviceControlBlock pParam;

    SYSCTRL_ClearClkGateMulti(1 << SYSCTRL_ClkGate_APB_PinCtrl);
	
    if (SPI_BASE == AHB_SSP0)
	{
        SYSCTRL_ClearClkGateMulti(1 << SYSCTRL_ClkGate_AHB_SPI0);
        SYSCTRL_SelectSpiClk(SPI_PORT_0, SYSCTRL_CLK_PLL_DIV_7);	//SPI时钟主控分频 336 / 7 = 48M
        PINCTRL_SetPadMux(WS2812B_DO, IO_SOURCE_SPI0_MOSI_OUT);
		PINCTRL_SetPadMux(IO_NOT_A_PIN, IO_SOURCE_SPI0_CLK_OUT);
    }
	else if (SPI_BASE == APB_SSP1)
	{
        SYSCTRL_ClearClkGateMulti(1 << SYSCTRL_ClkGate_APB_SPI1);
        SYSCTRL_SelectSpiClk(SPI_PORT_1, SYSCTRL_CLK_SLOW);
        PINCTRL_SetPadMux(WS2812B_DO, IO_SOURCE_SPI1_MOSI_OUT);
    } else
	{
        return 0xff;
    }

    memset(&pParam, 0, sizeof(apSSP_sDeviceControlBlock));
	
    pParam.eSclkDiv = LED_WS2812_SPI_SPEED;	// 48 / 2 * (2 + 1) = 8M

    pParam.eDataSize = SPI_DATALEN_32_BITS;
    pParam.eReadWriteMode = SPI_TRANSMODE_WRITE_ONLY;
    pParam.eWriteTransCnt = TRANS_DATA_NUM;
    pParam.TxThres = 4;
    apSSP_DeviceParametersSet(SPI_BASE, &pParam);
    apSSP_SetTxDmaEn(SPI_BASE, 1);

//	log_printf("SPI0: %dHZ\n", SYSCTRL_GetClk(SYSCTRL_ITEM_AHB_SPI0));
	
    return 0;
}

DMA_Descriptor descriptor_spi __attribute__((aligned (8)));

static uint32_t DMA_cb_isr(void *user_data)
{
    uint32_t state = DMA_GetChannelIntState(SPI_DMA_TX_CHANNEL);
	DMA_ClearChannelIntState(SPI_DMA_TX_CHANNEL, state);

	while(apSSP_GetSPIActiveStatus(WS2812_SPI_DRV_PORT));

	Test_Dma_Send_OK = 0;
	
    return 0;
}

_RAM_CODE_ static void LED_StartTrans(void)
{
	apSSP_ResetTxFifo(WS2812_SPI_DRV_PORT);
	
	descriptor_spi.TranSize = TRANS_DATA_NUM;
	descriptor_spi.SrcAddr = (uint32_t)ledData;
	SPI_SET_WRITE_CNT(descriptor_spi.TranSize);
	DMA_EnableChannel(SPI_DMA_TX_CHANNEL, &descriptor_spi);
	apSSP_WriteCmd(WS2812_SPI_DRV_PORT, 0x00, 0x00);
}

/*
	灯光模式
*/
/*
	R :0 ~ 7	G :8 ~ 15	B :16 ~ 23
*/
_RAM_CODE_ static void LED_Updata_Buff(uint32_t* Data_Buff, uint8_t* Data_R,  uint8_t* Data_G, uint8_t* Data_B, uint16_t Data_Size)
{
	uint8_t Tmep_Buff[24] = {0x00};
	uint8_t R_data = 0,G_data = 0,B_data = 0;
	uint8_t H_R_Data = 0,L_R_Data = 0;
	uint8_t H_G_Data = 0,L_G_Data = 0;
	uint8_t H_B_Data = 0,L_B_Data = 0;
	
	for(uint16_t i = 0; i < Data_Size; i++)
	{
		R_data = Data_R[i];
		G_data = Data_G[i];
		B_data = Data_B[i];
		
		for(uint8_t j = 0; j < 4; j++)
		{
			for(uint8_t k = 0; k < 2; k++)
			{
				if(k == 0)
				{
					if(R_data & 0x80)	H_R_Data = LED_WS2812_HIGH;
					else				H_R_Data = LED_WS2812_LOW;

					if(G_data & 0x80)	H_G_Data = LED_WS2812_HIGH;
					else				H_G_Data = LED_WS2812_LOW;

					if(B_data & 0x80)	H_B_Data = LED_WS2812_HIGH;
					else				H_B_Data = LED_WS2812_LOW;
				}
				else
				{
					if(R_data & 0x80)	L_R_Data = LED_WS2812_HIGH;
					else				L_R_Data = LED_WS2812_LOW;

					if(G_data & 0x80)	L_G_Data = LED_WS2812_HIGH;
					else				L_G_Data = LED_WS2812_LOW;
                  
					if(B_data & 0x80)	L_B_Data = LED_WS2812_HIGH;
					else				L_B_Data = LED_WS2812_LOW;
				}
				R_data <<= 1;
				G_data <<= 1;
				B_data <<= 1;
			}
			Tmep_Buff[j + 4] = ((H_R_Data << 4) & 0XF0) | (L_R_Data & 0X0F);
			Tmep_Buff[j + 0] = ((H_G_Data << 4) & 0XF0) | (L_G_Data & 0X0F);
			Tmep_Buff[j + 8] = ((H_B_Data << 4) & 0XF0) | (L_B_Data & 0X0F);
		}
		
		Data_Buff[i * 3 + 0] = (Tmep_Buff[0] << 24)  | (Tmep_Buff[1] << 16)  | (Tmep_Buff[2] << 8)  | (Tmep_Buff[3]);
		Data_Buff[i * 3 + 1] = (Tmep_Buff[4] << 24)  | (Tmep_Buff[5] << 16)  | (Tmep_Buff[6] << 8)  | (Tmep_Buff[7]);
		Data_Buff[i * 3 + 2] = (Tmep_Buff[8] << 24)  | (Tmep_Buff[9] << 16)  | (Tmep_Buff[10] << 8) | (Tmep_Buff[11]);
	}
}

_RAM_CODE_ void LED_Start_Dma(void)
{
    if(Test_Dma_Send_OK == 0)
    {
		Test_Dma_Send_OK = 1;
		LED_Updata_Buff(ledData, Led_R_Data, Led_G_Data, Led_B_Data, RGB_LED_MAX_NUM);
		LED_StartTrans();
	}
}

static uint8_t LED_DmaInit(SSP_TypeDef * SPI_BASE)
{
    uint8_t ret;
	
    SYSCTRL_ClearClkGateMulti(1 << SYSCTRL_ClkGate_APB_DMA);
	
    platform_set_irq_callback(PLATFORM_CB_IRQ_DMA, DMA_cb_isr, 0);
	
    ret = DMA_PrepareMem2Peripheral(&descriptor_spi,
                              SYSCTRL_DMA_SPI0_TX,
                              ledData,
                              DMA_TRANS_SIZE,
                              DMA_ADDRESS_INC,
                              0 | (2 << 24));
    return ret;
}



volatile uint32_t blink_color  = COLOR_GREEN;
volatile uint16_t blink_delay  = 500;
volatile uint8_t blink_style   = 2;

void blink_set(const uint32_t color, const blink_style_t style)
{

    switch (style)
    {
    case BLINK_ON:
        blink_style = 1;
        blink_color = color;
        blink_delay = 500;
        break;
    case BLINK_OFF:
        blink_style = 0;
        blink_color = COLOR_BLACK;
        blink_delay = 500;
        break;

    case BLINK_FAST:
        blink_style = 2;
        blink_color = color;
        blink_delay = 100;
        break;

    case BLINK_SLOW:
        blink_style = 2;
        blink_color = color;
        blink_delay = 500;
        break;
    default:
        break;
    }
}


enum app_state last_state;

void show_app_state(enum app_state state)
{
    last_state = state;
    switch (state)
    {
        case APP_ADV:
            blink_set(COLOR_GREEN, BLINK_SLOW);
            break;
        case APP_CONN:
            blink_set(COLOR_BLUE, BLINK_SLOW);
            break;
        case APP_POWER_LOW:
             blink_set(COLOR_RED, BLINK_FAST);
            break;
        default:
            blink_set(COLOR_RED, BLINK_OFF);
            break;
    }
}

void restore_show_app_state(void)
{
    switch (last_state)
    {
        case APP_ADV:
            blink_set(COLOR_GREEN, BLINK_SLOW);
            break;
        case APP_CONN:
            blink_set(COLOR_BLUE, BLINK_SLOW);
            break;
        case APP_POWER_LOW:
             blink_set(COLOR_RED, BLINK_FAST);
            break;
        default:
            blink_set(COLOR_RED, BLINK_OFF);
            break;
    }
}
static void rgb_led_task(void *pdata)
{
    uint8_t blink = 0;
    bsp_led_on_off(1);

    for (;;)
    {
        vTaskDelay(pdMS_TO_TICKS(blink_delay));
        switch(blink_style){
            case 0:led_mode_show(COLOR_BLACK);break;
            case 1:led_mode_show(blink_color);break;
            case 2:        
                led_mode_show(blink ? blink_color:COLOR_BLACK);
                blink = !blink;
                break;
        }

    }
}


uint8_t LED_Init(void)
{   
	//on_off_status = 1;
	
    if (LED_SpiInit(WS2812_SPI_DRV_PORT)) {
        //log_printf("LED_SpiInit fail!\r\n");
        return 0xff;
    }

    if (!LED_DmaInit(WS2812_SPI_DRV_PORT)) 
	{
      //  log_printf("LED_Init successful!\r\n");
     
        return 0;
    }
     
    return 0xff;
}

void LED_Task_Init(void){

   xTaskCreate(rgb_led_task, "rgb", configMINIMAL_STACK_SIZE*1, NULL, 10, NULL); 

}

void bsp_led_on_off(uint8_t on_off)
{
	on_off_status = on_off;
}

void LED_uninit(void)
{
	Test_Dma_Send_OK = 0;
	on_off_status = 0;
}


static _RAM_CODE_ void led_mode_show(uint32_t color)
{
    static uint32_t color_back = 0xff000000;
    if(color_back == color) return;
    color_back = color;
	uint8_t i = 0;
	if(on_off_status == 1)
	{	
		for(i = 0; i < RGB_LED_MAX_NUM; i++)
		{		
            Led_R_Data[i] = (color>>0)&0xff;//LED_Mix_Colour_Tab[Temp_Count][0];
            Led_G_Data[i] = (color>>8)&0xff;//LED_Mix_Colour_Tab[Temp_Count][1];
            Led_B_Data[i] = (color>>16)&0xff;//LED_Mix_Colour_Tab[Temp_Count][2];
		}

		LED_Start_Dma();
	}
}